#ifndef xpack_docker_page_array
#define xpack_docker_page_array
#pragma push_macro("xuser")
#undef  xuser
#define xuser mixc::docker_page_array::inc
#include"adapter/multi_push.hpp"
#include"adapter/random_access.hpp"
#include"algo/var_array.hpp"
#include"dumb/disable_copy.hpp"
#include"dumb/move.hpp"
#include"macro/xexport.hpp"
#include"macro/xunlikely.hpp"
#include"utils/memory.hpp"
#include"utils/value_holder.hpp"
#pragma pop_macro("xuser")

#define xpage_array_com(NAME)                                               \
    item_t **   table_ptr   = m_table;                                      \
    item_t ** & NAME        = conf_t::is_static_page ? table_ptr : m_table_ptr

namespace mixc::docker_page_array{
    template<
        uxx init_size_v = 1,
        uxx max_pages_v = not_exist,
        inc::memory::is_allocator allocator_t = inc::memory::default_allocator_t
    >
    requires((init_size_v & (init_size_v - 1)) == 0 and init_size_v > 0)
    struct page_array_conf{
        template<uxx init_sizex_v = init_size_v>
        using set_init_size = page_array_conf<init_sizex_v, max_pages_v, allocator_t>;

        // 最大页表个数，范围 [2, xbitsof(uxx)]
        template<uxx max_pagesx_v = max_pages_v>
        using set_max_pages = page_array_conf<init_size_v, max_pagesx_v, allocator_t>;

        // 设置分配器，需要符合 is_allocator 约束
        template<inc::memory::is_allocator allocatorx_t = allocator_t>
        using set_allocator = page_array_conf<init_size_v, max_pages_v, allocatorx_t>;

        static constexpr auto init_size             = init_size_v;
        static constexpr auto is_static_page        = max_pages_v != not_exist;
        static constexpr auto page_type             = max_pages_v != not_exist ? inc::with_fixed_page_table : not inc::with_fixed_page_table;
        static constexpr auto max_pages             = is_static_page ? max_pages_v : 1;
    };

    template<class itemx_t, class conf_t = page_array_conf<>>
    struct page_array;

    #define xpage_array_conf_t  page_array_conf<init_size_v, max_pages_v, allocator_t>

    template<
        class itemx_t,
        uxx init_size_v,
        uxx max_pages_v,
        inc::memory::is_allocator allocator_t
    >
    xstruct(
        xspec(page_array, itemx_t, xpage_array_conf_t),
        xpubb(inc::disable_copy),
        xpubb(inc::random_access<page_array<itemx_t, xpage_array_conf_t>, itemx_t>),
        xpubb(
            inc::multi_push<
                page_array<itemx_t, xpage_array_conf_t>, itemx_t
            >
        ),
        xpubf(m_length, uxx),
        xasso(itemx_t)
    )
    private:
        using conf_t        = xpage_array_conf_t;
        #undef                xpage_array_conf_t
    public:
        using inc::multi_push<the_t, itemx_t>::push;
        using item_t        = itemx_t;
        using var_t         = inc::var_array<init_size_v, conf_t::page_type>;
    private:
        union{
            mutable item_t *    m_table[conf_t::max_pages];
            mutable item_t **   m_table_ptr;
        };

        static constexpr auto alloc_lambda(){
            return [](uxx bytes){
                return allocator_t::template alloc<void>(inc::memory::size(bytes));
            };
        }

        static constexpr auto free_lambda(){
            return [](const void * ptr, uxx bytes){
                allocator_t::template free_with_destroy<void>(ptr, inc::memory::size(bytes));
            };
        }

    public:
        xprops()
            xpubget(length, uxx);
        $

        xprops_operator()

    public:
        constexpr page_array():
            m_length(0),
            m_table_ptr(nullptr){
        }

        void push(item_t & item){
            xpage_array_com(tab);
            var_t::push(xmodify(tab), xmodify(m_length), item, alloc_lambda(), free_lambda());
        }

        void push(item_t && item){
            xpage_array_com(tab);
            var_t::push(xmodify(tab), xmodify(m_length), (item_t &&)/*需要再次转发*/item, alloc_lambda(), free_lambda());
        }

        inc::value_holder<item_t> pop(){
            xunlikely(m_length == 0){
                return {};
            }

            char buf[sizeof(item_t)];
            item_t *    value       = (item_t *)buf;
            xpage_array_com(tab);
            var_t::pop_to_mirror(xmodify(tab), xmodify(m_length), value, alloc_lambda(), free_lambda());
            return inc::move(*value);
        }

        void clear(){
            xpage_array_com(tab);
            var_t::clear(xmodify(tab), xmodify(m_length), free_lambda());
        }

        ~page_array(){
            this->clear();
        }

    private:
        friend inc::random_access<the_t, item_t>;

        item_t & random_get(uxx index) const {
            xpage_array_com(tab);
            return var_t::access(tab, index);
        }
    $
}

namespace mixc::docker_page_array::origin{
    using mixc::docker_page_array::page_array;
    using mixc::docker_page_array::page_array_conf;
}

#undef  xpage_array_com
#endif

xexport_space(mixc::docker_page_array::origin)
